package com.xiaoniu.mc.hystrix;


import com.netflix.hystrix.*;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @类描述：
 * @创建人：林继丰
 * @创建时间：2017/9/20 15:38
 * @版权：Copyright (c) 深圳市牛鼎丰科技有限公司-版权所有.
 */
public class SelfHystrixCommand extends HystrixCommand<Object> {

    private MethodInvocation invocation;
    private HystrixConfig hystrixConfig;

    public SelfHystrixCommand(MethodInvocation invocation, HystrixConfig hystrixConfig) {
        super(setter(hystrixConfig));//线程池为30
        this.invocation = invocation;
        this.hystrixConfig = hystrixConfig;
    }

    public static HystrixCommand.Setter setter(HystrixConfig hystrixConfig) {
        return HystrixCommand.Setter
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(hystrixConfig.getGroupKey()))
                .andCommandKey(HystrixCommandKey.Factory.asKey(hystrixConfig.getCommandKey()))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
                                .withExecutionTimeoutInMilliseconds(Integer.parseInt(hystrixConfig.getTimeoutInMilliseconds()))
                                .withCircuitBreakerEnabled(Boolean.parseBoolean(hystrixConfig.getCircuitBreakerEnabled()))
                                .withCircuitBreakerRequestVolumeThreshold(Integer.parseInt(hystrixConfig.getCircuitBreakerRequestVolumeThreshold()))
                                .withCircuitBreakerSleepWindowInMilliseconds(30000)
                                .withFallbackIsolationSemaphoreMaxConcurrentRequests(Integer.MAX_VALUE)
//                        .withCircuitBreakerErrorThresholdPercentage(50)

                )
                //ThreadPool配置
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(hystrixConfig.getThreadPoolKey()))
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(Integer.parseInt(hystrixConfig.getCoreSize()))
                        .withMaxQueueSize(Integer.parseInt(hystrixConfig.getMaxQueueSize())))
                ;
    }

    @Override
    protected Object run() throws Exception {
        try {
            return invocation.proceed();
        } catch (Throwable throwable) {
            throw new RuntimeException("调用错误");
        }
    }

    @Override
    protected Object getFallback() {
        if(StringUtils.isNotBlank(hystrixConfig.getFallBackClass())){
            try {
                Class clazz = Class.forName(hystrixConfig.getFallBackClass());
                Class[] argumentClazzes = new Class[invocation.getArguments().length];
                for (int i = 0; i < invocation.getArguments().length; i++) {
                    argumentClazzes[i] = invocation.getArguments()[i].getClass();
                }
                Method fallBackMethod = clazz.getMethod(hystrixConfig.getFallBackMethod(),argumentClazzes);
                return fallBackMethod.invoke(clazz.newInstance(), invocation.getArguments());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}